<template>
  <div class="hello">
    <p>{{room.id + "-" + self.uid}}</p>
    <el-row :gutter="20">
      <el-col :span="4" v-for="(k,index) in users" :key="k.uid">
        <el-card v-bind:class="{bule:k.isActive}"  class="grid-content" shadow="hover"
                 @click.native="sendDatachannelMsg(k)">
          {{ k.uid }}
        </el-card>
      </el-col>
    </el-row>
    <p>{{chatContent}}</p>
  </div>
</template>

<script>
  export default {
    name: 'HelloWorld',
    data() {
      return {
        serverSocket: null,
        self: {uid: '', name: '', appId: ''},
        room: {id: '', name: '', maxSize: ''},
        users: [],
        peerConfig: {
          iceServers: [
            {urls: 'stun:p2p.playwithother.com:3478'},
            {urls: 'turn:p2p.playwithother.com:3478', username: 'ivymobile', credential: '123456'}
          ]
        },
        chatContent: ''
      }
    },
    methods: {
      initSocket: function () {
        const self = this;
        this.self.uid = Math.random().toString(36).substr(2);
        this.serverSocket = new WebSocket("ws://p2p.playwithother.com:10000");
        this.serverSocket.onopen = function (e) {
          let initParams = {
            action: 'init',
            uid: self.self.uid,
            uuid: "-1",
            name: self.self.uid,
            appId: "benchmark",
            result: false
          };
          self.serverSocket.send(JSON.stringify(initParams))
        };
        this.serverSocket.onmessage = function (e) {
          let obj = JSON.parse(e.data);
          console.log(e.data);
          let action = obj.action;
          switch (action) {
            case "init":
              self.self.uid = obj.self.uid;
              self.self.uuid = obj.self.uuid;
              self.self.name = obj.self.name;
              self.self.appId = obj.self.appId;
              self.randomJoin();
              break;
            case "randomJoin":
              if (obj.result) {
                self.room.id = obj.room.id;
                self.room.name = obj.room.name;
                self.room.maxSize = obj.room.maxSize;
                obj.user.forEach(u => {
                  self.addUser(u);
                  self.subscribe(u.uid)
                });
              }
              break;
            case "disconnect":
              let uid = obj.uid;
              self.removeUser(uid);
              break;
            case "message":
              let from = obj.from;
              switch (obj.type) {
                case "subscribe":
                  let findUser = self.findUser(from);
                  if (findUser === undefined) {
                    self.addUser({
                      uid: from,
                      name: obj.name,
                      appId: obj.appId
                    })
                  }
                  self.createOffer(from);
                  break;
                case "offer":
                  self.createAnswer(from, obj.payload);
                  break;
                case "answer":
                  self.receiveAnswer(from, obj.payload);
                  break;
                case "candidate":
                  self.addIceCandidate(from, obj.payload);
                  break;
                default:
                  console.log("default type");
              }
              break;
            default:
          }
        };
      },
      randomJoin: function () {
        let randomJoinParams = {
          action: "randomJoin",
          isMaster: false,
          maxSize: 6
        };
        this.serverSocket.send(JSON.stringify(randomJoinParams))
      },
      sendMessage2Other: function (to, type, payload) {
        let messageParams = {
          to: to,
          type: type,
          roomId: this.room.id,
          payload: payload,
          action: "message"
        };
        this.serverSocket.send(JSON.stringify(messageParams))
      },
      addUser(user) {
        let self = this;
        user.pc = new RTCPeerConnection(this.peerConfig);
        user.pc.onicecandidate = function (ev) {
          if (ev.candidate) {
            self.sendMessage2Other(user.uid, "candidate", {
              label: ev.candidate.sdpMLineIndex,
              id: ev.candidate.sdpMid,
              candidate: ev.candidate.candidate
            })
          }
        };
        user.pc.onconnectionstatechange = function (ev) {
          console.log("onconnectionstatechange: " + user.pc.connectionState)
        };
        user.pc.oniceconnectionstatechange = function () {
          console.log("oniceconnectionstatechange: " + user.pc.iceConnectionState)
        };
        user.pc.onicegatheringstatechange = function (ev) {
          console.log("onicegatheringstatechange: " + user.pc.iceGatheringState)
        };
        user.pc.onsignalingstatechange = function (ev) {
          console.log("onsignalingstatechange: " + user.pc.signalingState)
        };
        user.pc.ondatachannel = function (ev) {
          console.log("ondatachannel: " + ev.channel.label)
        };
        user.dc = user.pc.createDataChannel("ivy", {negotiated: true, id: 0});
        user.dc.onopen = function () {
          user.isActive = true;
          user.dc.send('Hello from ' + user.uid);
        };
        user.dc.onbufferedamountlow = function (ev) {
          console.log("onbufferedamountlow: " + ev.returnValue)
        };
        user.dc.onmessage = function (ev) {
          console.log("datachannel ------- " + ev.data)
        };
        user.dc.onclose = function (ev) {
          user.isActive = false;
          console.log("onclose:" + ev.returnValue)
        };
        user.dc.onerror = function (ev) {
          console.log("onerror: " + ev.error)
        };
        user.isActive = false;
        this.users.push(user);
      },
      subscribe: function (uid) {
        this.sendMessage2Other(uid, "subscribe", null)
      },
      createOffer: function (uid) {
        let self = this;
        let user = this.findUser(uid);

        if (user !== undefined) {
          user.pc.createOffer().then(function (sdp) {
            user.pc.setLocalDescription(sdp);
            console.log(user.uid + " createOffer");
            self.sendMessage2Other(user.uid, "offer", sdp)
          }).catch(function (e) {
            console.log(e)
          })
        } else {
          console.log("user is not exists:" + uid)
        }
      },
      createAnswer: function (uid, payload) {
        let self = this;
        let user = this.findUser(uid);
        if (user !== undefined) {
          console.log(user.uid + " createAnswer");
          user.pc.setRemoteDescription(new RTCSessionDescription(payload), function () {
          }, self.reportError);
          user.pc.createAnswer().then(function (sdp) {
            user.pc.setLocalDescription(sdp);
            self.sendMessage2Other(user.uid, "answer", sdp)
          })
        }
      },
      receiveAnswer: function (uid, payload) {
        let self = this;
        let user = this.findUser(uid);
        if (user !== undefined) {
          console.log(user.uid + " receiveAnswer");
          user.pc.setRemoteDescription(new RTCSessionDescription(payload), function () {
          }, self.reportError)
        }
      },
      addIceCandidate: function (uid, payload) {
        let user = this.findUser(uid);
        if (user !== undefined) {
          console.log(user.uid + " addIceCandidate");
          user.pc.addIceCandidate(new RTCIceCandidate({
            sdpMLineIndex: payload.label,
            sdpMid: payload.id,
            candidate: payload.candidate
          }));
        }
      },
      sendDatachannelMsg: function (row) {
        console.log(row.dc);
        row.dc.send(JSON.stringify(row));
      },
      findUser: function (uid) {
        return this.users.find(function (user) {
          return user.uid === uid
        })
      },
      removeUser: function (uid) {
        let index = this.indexOfUser(uid);
        this.users.splice(index, 1)
      },
      indexOfUser: function (uid) {
        for (let i = 0; i < this.users.length; i++) {
          if (this.users[i].uid === uid) return i;
        }
        return -1;
      },
      reportError: function (error) {
        console.log(error)
      }
    },
    mounted() {
      this.initSocket();
    }
  }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .el-col {
    margin-bottom: 20px;
    border-radius: 4px;
  }

  .grid-content {
    background: red;
    border-radius: 4px;
    min-height: 20px;
    text-align: center;
    color: #fff;
    line-height: 40px;
  }

  .bule {
    background: dodgerblue;
  }

</style>
